package com.zuoban.shiro;



import com.zuoban.shiro.chain.AuthChain;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;


import java.math.BigInteger;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;



@Slf4j
public class AuthRealm extends AuthorizingRealm {


    @Autowired
    private List<AuthChain> authChains;


    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        return info;
    }


    // 认证流程

    /**
     * 从shiro的主体中取出token
     *  1、token是伪造，用户恶意伪造请求头，需要进行拦截掉
     *  2、token有效，但是，token本身过期
     *  3、token有效，但是在redis中没找到这个token，证明token已过期，不允许放行
     *  3、token有效，解析成功，取出userId 在数据库中进行查询，查询失败，需要拦截
     *  4、token有效，解析成功，查询成功，有该用户 进行放行
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String token = (String) authenticationToken.getPrincipal();
        AtomicReference<BigInteger> userId = new AtomicReference<>(BigInteger.ZERO);
        // 引入责任链模式+Order注解 实现认证流程 Order值越小越先执行
        authChains.forEach(authChain -> userId.set(authChain.authentication(token)));
        // 在这个地方设置的三个参数 可以通过SecurityUtils.getSubject()方法拿到
        return new SimpleAuthenticationInfo(userId, token, "authRealm");

    }
}
